﻿using System;
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;
using System.Linq;
namespace LitTools
{
    /// <summary>
    /// GM管理类
    /// </summary>
    public static class GMUtility
    {
        //方法字典，或者叫指令字典
        private static Dictionary<string, CommondInfo> commandDict;
        //是否初始化过了
        private static bool isInit;

        #region 公有方法
        /// <summary>
        /// 初始化，获取所有标记了指令的类
        /// </summary>
        public static void Init()
        {
            if (isInit) return;
            commandDict = new Dictionary<string, CommondInfo>();
            var gmClasses = CSUtility.GetClassWithAttirbute<GMClassAttribute>();
            foreach (var gmClass in gmClasses)
            {
                var methods = gmClass.GetMethods();
                foreach (var method in methods)
                {
                    var attributes = method.GetCustomAttributes(typeof(GMCommondAttribute), false);
                    if (attributes == null) continue;
                    if (attributes.Length <= 0) continue;
                    for (int i = 0; i < attributes.Length; i++)
                    {
                        if(attributes[i] is GMCommondAttribute gmc)
                        {
                            if (commandDict.ContainsKey(gmc.cmd))
                            {
                                string addObj = commandDict[gmc.cmd].callObj.GetType().ToString();
                                string addMethod = commandDict[gmc.cmd].callMethod.Name;
                                Debug.LogError($"same command has been added {addObj}.{addMethod},will add is" +
                                    $"{gmClass}.{method.Name}");
                                continue;
                            }
                            commandDict.Add(gmc.cmd, new CommondInfo()
                            {
                                callObj = Activator.CreateInstance(gmClass),
                                callMethod = method,
                            });
                            break;
                        }
                    }
                }
            }
            isInit = true;
        }

        /// <summary>
        /// Call指令
        /// </summary>
        /// <param name="inputStr"></param>
        /// <returns></returns>
        public static string Call(string inputStr)
        {
            if (!isInit) Init();
            var tempStr = inputStr.Split(' ');
            var param = new List<string>();
            for (int i = 0; i < tempStr.Length; i++)
            {
                param.Add(tempStr[i]);
            }
            if (commandDict.ContainsKey(tempStr[0]))
            {
                var obj = commandDict[tempStr[0]].callObj;
                var method = commandDict[tempStr[0]].callMethod;
                var info = method.GetCustomAttributes(typeof(GMCommondAttribute), false)[0] as GMCommondAttribute;

                string result = method.Invoke(obj
                    , new object[] { param.TakeLast(param.Count - 1).ToArray() }) as string;
                result += $"\n desc:{info.desc}";
                Debug.Log("GMCommond: " + result);
                return result;
            }
            else
            {
                return "command not find";
            }
        }

        #endregion

        /// <summary>
        /// 指令信息类
        /// </summary>
        class CommondInfo
        {
            /// <summary>
            /// 调用的类
            /// </summary>
            public object callObj;
            /// <summary>
            /// 调用的方法
            /// </summary>
            public MethodInfo callMethod;
        }
    }

    /// <summary>
    /// GMClass特性
    /// </summary>
    public class GMClassAttribute : Attribute
    {

    }

    /// <summary>
    /// GMCommond特性，
    /// 标记可以通过指令调用的方法
    /// </summary>
    public class GMCommondAttribute : Attribute
    {
        public string cmd;
        public string desc;
        public GMCommondAttribute(string cmd, string desc)
        {
            this.cmd = cmd;
            this.desc = desc;
        }
    }
}